﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Net;
using System.IO;
using System.IO.IsolatedStorage;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Visifire.Charts;
using Visifire.Commons;

using OneStop.Calculations;

namespace OneStop.UI
{
    public partial class Page : UserControl
    {

        public Page()
        {
            InitializeComponent();

            Application.Current.Host.Content.FullScreenChanged += new EventHandler(Content_FullScreenChanged);
        }

        public MainProvider provider;

        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            //Application.Current.CheckAndDownloadUpdateCompleted += new CheckAndDownloadUpdateCompletedEventHandler(Current_CheckAndDownloadUpdateCompleted);

            //Application.Current.CheckAndDownloadUpdateAsync();

            provider = (MainProvider)this.Resources["Provider"];

            initialisePrefs();            

            NewProfile_Click(sender, EventArgs.Empty);
        }

        void Current_CheckAndDownloadUpdateCompleted(object sender, CheckAndDownloadUpdateCompletedEventArgs e)
        {
            if (e.UpdateAvailable) 
            { 
                MessageBox.Show("An update has been downloaded. " + 
                    "Restart the application to run the new version."); 
            } 
            else if (e.Error != null && e.Error is PlatformNotSupportedException) 
            { 
                MessageBox.Show("An application update is available, " + "but it requires a new version of Silverlight. " + "Visit the application home page to upgrade."); 
            }
        }

        private void calc()
        {
            Profile p = new Profile();

            provider.ProfilePrimary = p;
            ViewPrimary.IsChecked = true;

            p.Gases.Add(new Gas(0.21, .35));
            p.Gases.Add(new Gas(0.5, 0));

            p.InputSegments.Add(new SegmentDive(50, 25, p.Gases[0], 1.25));
            //p.InputSegments.Add(new SegmentDive(6, 0, p.Gases[1], 1.55));

            provider.Refresh();

            calc(p);
        }

        public void calc(Profile p)
        {
            p.Reset();

            p.IsOCDeco = (bool)IsOCDeco.IsChecked;

            ProfileStatus status = p.DoDive();

            provider.ProfilePrimary = p;

            if (p.InputSegments.Count > 0)
            {
                switch (status)
                {
                    case ProfileStatus.Success:

                        p.DoGasCalcs();

                        if (provider.IsCCRDive)
                        {
                            Profile b = (Profile)p.Clone();

                            b.Reset();
                            b.Model.Gradient.GfLow = Prefs.Current.GfLowBailout;
                            b.Model.Gradient.GfHigh = Prefs.Current.GfHighBailout;

                            SegmentDive last = b.InputSegments[b.InputSegments.Count - 1];
                            b.InputSegments.Add(new SegmentDive(last.Depth, 0, last.Gas, 0));
                            b.IsOCDeco = true;

                            b.DoDive();
                            b.DoGasCalcs();

                            provider.ProfileBailout = b;
                        }

                        bindOutputGrid();

                        bindChart();

                        break;
                    case ProfileStatus.ProcessingError:
                        break;
                    case ProfileStatus.InfiniteDeco:
                        break;
                    case ProfileStatus.NothingToProcess:
                        break;
                    case ProfileStatus.CeilingViolation:
                        break;
                }
            }
            else
            {
                provider.OutputSegments = null;
                OutputChart.Series.Clear();
                provider.ProfileBailout = null;
            }

            provider.Refresh();
        }

        private void bindChart()
        {
            OutputChart.Series.Clear();
            GasChart.Series.Clear();
            OutputChart.Series.Add(buildSeries(provider.ProfilePrimary.OutputSegments, "Dive"));
            OutputChart.Series.Add(buildGfSeries(provider.ProfilePrimary.OutputSegments, "Gf Dive"));

            if (provider.IsCCRDive)
            {
                OutputChart.Series.Add(buildSeries(provider.ProfileBailout.OutputSegments, "Bailout"));
                OutputChart.Series.Add(buildGfSeries(provider.ProfileBailout.OutputSegments, "Gf Bailout"));
                
                GasChart.Series.Add(buildGasSeries(provider.ProfileBailout.Gases, "Bailout Gases"));
            }
            else
            {
                GasChart.Series.Add(buildGasSeries(provider.ProfilePrimary.Gases, "Dive Gases")); 
            }

        }

        private DataSeries buildGasSeries(ObservableCollection<Gas> gases, string name)
        {
            DataSeries series = new DataSeries();

            series.RenderAs = RenderAs.Pie;
            series.MarkerEnabled = false;
            series.Name = name;

            foreach (Gas g in gases)
            {
                series.DataPoints.Add(new DataPoint() { AxisXLabel = g.ShortName, YValue = g.Volume });
            }

            return series;
        }

        private DataSeries buildGfSeries(ObservableCollection<SegmentAbstract> segments, string name)
        {
            DataSeries series = new DataSeries();

            series.RenderAs = RenderAs.Line;
            series.MarkerEnabled = false;
            series.LineThickness = 1;
            series.Opacity = 70;
            series.Name = name;
            series.AxisYType = AxisTypes.Secondary;

            foreach (SegmentAbstract s in segments)
            {
                series.DataPoints.Add(new DataPoint() { AxisXLabel = s.RunTime.ToString(), YValue = s.Gf });
            }
            return series;
        }

        private DataSeries buildSeries(ObservableCollection<SegmentAbstract> segments, string name)
        {
            DataSeries series = new DataSeries();

            series.RenderAs = RenderAs.Line;
            series.MarkerEnabled = true;
            series.MarkerSize = 6;
            series.LineThickness = 3;
            series.Name = name;

            series.DataPoints.Add(new DataPoint() { XValue = 0, YValue = 0 });

            foreach (SegmentAbstract s in segments)
            {
                series.DataPoints.Add(new DataPoint() { AxisXLabel = s.RunTime.ToString(), YValue = s.Depth * -1, ToolTipText = s.ToString() });
            }

            return series;
        }

        private void GasEdit_Click(object sender, RoutedEventArgs e)
        {
            GasAdmin g = new GasAdmin(provider);

            g.Show();
        }

        private void SegmentAdd_Click(object sender, RoutedEventArgs e)
        {
            provider.ProfilePrimary.InputSegments.Add(new SegmentDive());
        }

        private void DeleteRow_Click(object sender, RoutedEventArgs e)
        {
            if (InputGrid.SelectedIndex > -1)
                provider.ProfilePrimary.InputSegments.RemoveAt(InputGrid.SelectedIndex);
        }

        private void MoveDown_Click(object sender, RoutedEventArgs e)
        {
            if (InputGrid.SelectedIndex > -1 &&
                InputGrid.SelectedIndex < provider.ProfilePrimary.InputSegments.Count - 1)
            {
                int index = InputGrid.SelectedIndex;
                SegmentDive s = provider.ProfilePrimary.InputSegments[index];
                provider.ProfilePrimary.InputSegments.RemoveAt(index);
                provider.ProfilePrimary.InputSegments.Insert(index + 1, s);
            }
        }

        private void MoveUp_Click(object sender, RoutedEventArgs e)
        {
            if (InputGrid.SelectedIndex > -1 &&
                InputGrid.SelectedIndex > 0)
            {
                int index = InputGrid.SelectedIndex;
                SegmentDive s = provider.ProfilePrimary.InputSegments[index];
                provider.ProfilePrimary.InputSegments.RemoveAt(index);
                provider.ProfilePrimary.InputSegments.Insert(index - 1, s);
            }
        }

        private void AddRow_Click(object sender, RoutedEventArgs e)
        {
            provider.ProfilePrimary.InputSegments.Add(new SegmentDive());
        }

        private void RunCalc_Click(object sender, EventArgs e)
        {
            calc(provider.ProfilePrimary);
        }

        void Content_FullScreenChanged(object sender, EventArgs e)
        {
            provider.Refresh();
        }

        private void OutOfBrowser_Click(object sender, EventArgs e)
        {
            if (!Application.Current.IsRunningOutOfBrowser)
            {
                if (Application.Current.InstallState == InstallState.NotInstalled)
                {
                    Application.Current.Install();
                }
                else
                {
                    MessageBox.Show("Application already installed.");
                }
            }
        }

        private void bindOutputGrid()
        {
            if (ViewPrimary.IsChecked || !provider.IsCCRDive)
            {
                provider.OutputSegments = provider.ProfilePrimary.OutputSegments;
            }
            else
            {
                provider.OutputSegments = provider.ProfileBailout.OutputSegments;
            }
        }

        private void SaveProfile_Click(object sender, EventArgs e)
        {
            if (provider.ProfilePrimary.Name == null)
            {
                SaveAs_Click(sender, e);
            }
            else
            {
                saveProfile(provider.ProfilePrimary.Name);
            }
        }

        SaveProfile sp;

        private void SaveAs_Click(object sender, EventArgs e)
        {
            sp = new SaveProfile();

            sp.Closed += new EventHandler(SaveProfile_Closed);
            sp.DataContext = provider;

            sp.Show();
        }

        void SaveProfile_Closed(object sender, EventArgs e)
        {
            if ((bool)sp.DialogResult)
            {
                saveProfile(provider.ProfilePrimary.Name);
            }
        }

        private void saveProfile(string name)
        {
            using (IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication())
            {
                using (IsolatedStorageFileStream isfs = new IsolatedStorageFileStream(name, FileMode.Create, isf))
                {
                    provider.ProfilePrimary.Save(isfs);
                }

                provider.Refresh();
            }
        }

        private void initialisePrefs()
        {
            using (IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication())
            {
                if (isf.FileExists(provider.PrefsFilename))
                {
                    using (IsolatedStorageFileStream stream = isf.OpenFile(provider.PrefsFilename, FileMode.Open))
                    {
                        Prefs.Deserialize(stream);
                    }
                }
            }
        }

        private void OpenProfile_LoadProfile(object sender, LoadProfileEventArgs e)
        {
            using (IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication())
            {
                using (IsolatedStorageFileStream stream = isf.OpenFile(e.FileName, FileMode.Open)) 
                {
                    Profile p = Profile.Load(stream);
                    
                    calc(p);
                } 
            }
        }

        private void NewProfile_Click(object sender, EventArgs e)
        {
            calc();
        }

        private void DeleteRows_Click(object sender, System.Windows.RoutedEventArgs e)
        {
        	provider.ProfilePrimary.InputSegments.Clear();
        }

        private void AddGasRow_Click(object sender, System.Windows.RoutedEventArgs e)
        {
        	provider.ProfilePrimary.Gases.Add(new Gas());
        }

        private void DeleteGasRows_Click(object sender, System.Windows.RoutedEventArgs e)
        {
        	provider.ProfilePrimary.Gases.Clear();
        }

        private void PrefsUserControl_DefaultsSaved(object sender, EventArgs e)
        {
            using (IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication())
            {
                using (IsolatedStorageFileStream stream = isf.OpenFile(provider.PrefsFilename, FileMode.Create))
                {
                    Prefs.Serialize(stream);
                }
            }
        }

        private void DeleteGasRow_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            Gas g = provider.ProfilePrimary.Gases[GasList.SelectedIndex];
            provider.ProfilePrimary.Gases.Remove(g);

            foreach (SegmentDive s in provider.ProfilePrimary.InputSegments)
            {
                if (s.Gas == g)
                {
                    s.Gas = null;
                }
            }
        }

        private void ViewPrimary_Checked(object sender, EventArgs e)
        {
            bindOutputGrid();
        }
    }
}
